﻿namespace TNet
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Threading;

    public class SGameServer : FileServer
    {
        public const ushort gameID = 0x3600;
        public const bool isMultiThreaded = false;
        private bool mAllowUdp;
        private TNet.Buffer mBuffer;
        private TNet.List<Channel> mChannels = new TNet.List<Channel>();
        private Dictionary<IPEndPoint, TcpPlayer> mDictionaryEP = new Dictionary<IPEndPoint, TcpPlayer>();
        private Dictionary<int, TcpPlayer> mDictionaryID = new Dictionary<int, TcpPlayer>();
        private TcpListener mListener;
        private int mListenerPort;
        private object mLock = 0;
        private TNet.List<TcpPlayer> mPlayers = new TNet.List<TcpPlayer>();
        private Random mRandom = new Random();
        private TNet.List<uint> mTemp = new TNet.List<uint>();
        private Thread mThread;
        private long mTime;
        private UdpProtocol mUdp = new UdpProtocol();
        public string name = "Simple Game Server";
        public OnCustomPacket onCustomPacket;
        public OnPlayerAction onPlayerConnect;
        public OnPlayerAction onPlayerDisconnect;
        public OnShutdown onShutdown;

        private TcpPlayer AddPlayer(Socket socket)
        {
            TcpPlayer item = new TcpPlayer();
            item.StartReceiving(socket);
            this.mPlayers.Add(item);
            return item;
        }

        private BinaryWriter BeginSend(Packet type)
        {
            this.mBuffer = TNet.Buffer.Create();
            return this.mBuffer.BeginPacket(type);
        }

        private bool ChannelExists(int id)
        {
            for (int i = 0; i < this.mChannels.size; i++)
            {
                if (this.mChannels[i].id == id)
                {
                    return true;
                }
            }
            return false;
        }

        private Channel CreateChannel(int channelID, out bool isNew)
        {
            Channel channel;
            for (int i = 0; i < this.mChannels.size; i++)
            {
                channel = this.mChannels[i];
                if (channel.id == channelID)
                {
                    isNew = false;
                    if (channel.closed)
                    {
                        return null;
                    }
                    return channel;
                }
            }
            channel = new Channel {
                id = channelID
            };
            this.mChannels.Add(channel);
            isNew = true;
            return channel;
        }

        private void EndSend(bool reliable)
        {
            this.mBuffer.EndPacket();
            if (this.mBuffer.size > 0x400)
            {
                reliable = true;
            }
            for (int i = 0; i < this.mChannels.size; i++)
            {
                Channel channel = this.mChannels[i];
                for (int j = 0; j < channel.players.size; j++)
                {
                    TcpPlayer player = channel.players[j];
                    if (player.stage == TcpProtocol.Stage.Connected)
                    {
                        if ((reliable || !player.udpIsUsable) || ((player.udpEndPoint == null) || !this.mAllowUdp))
                        {
                            player.SendTcpPacket(this.mBuffer);
                        }
                        else
                        {
                            this.mUdp.Send(this.mBuffer, player.udpEndPoint);
                        }
                    }
                }
            }
            this.mBuffer.Recycle();
            this.mBuffer = null;
        }

        private void EndSend(IPEndPoint ip)
        {
            this.mBuffer.EndPacket();
            this.mUdp.Send(this.mBuffer, ip);
            this.mBuffer.Recycle();
            this.mBuffer = null;
        }

        private void EndSend(bool reliable, TcpPlayer player)
        {
            this.mBuffer.EndPacket();
            if (this.mBuffer.size > 0x400)
            {
                reliable = true;
            }
            if ((reliable || !player.udpIsUsable) || ((player.udpEndPoint == null) || !this.mAllowUdp))
            {
                player.SendTcpPacket(this.mBuffer);
            }
            else
            {
                this.mUdp.Send(this.mBuffer, player.udpEndPoint);
            }
            this.mBuffer.Recycle();
            this.mBuffer = null;
        }

        private void EndSend(bool reliable, Channel channel, TcpPlayer exclude)
        {
            this.mBuffer.EndPacket();
            if (this.mBuffer.size > 0x400)
            {
                reliable = true;
            }
            for (int i = 0; i < channel.players.size; i++)
            {
                TcpPlayer player = channel.players[i];
                if ((player.stage == TcpProtocol.Stage.Connected) && (player != exclude))
                {
                    if ((reliable || !player.udpIsUsable) || ((player.udpEndPoint == null) || !this.mAllowUdp))
                    {
                        player.SendTcpPacket(this.mBuffer);
                    }
                    else
                    {
                        this.mUdp.Send(this.mBuffer, player.udpEndPoint);
                    }
                }
            }
            this.mBuffer.Recycle();
            this.mBuffer = null;
        }

        private void Error(TcpPlayer p, string error)
        {
        }

        private TcpPlayer GetPlayer(int id)
        {
            TcpPlayer player = null;
            this.mDictionaryID.TryGetValue(id, out player);
            return player;
        }

        private TcpPlayer GetPlayer(IPEndPoint ip)
        {
            TcpPlayer player = null;
            this.mDictionaryEP.TryGetValue(ip, out player);
            return player;
        }

        private TcpPlayer GetPlayer(string name)
        {
            for (int i = 0; i < this.mPlayers.size; i++)
            {
                if (this.mPlayers[i].name == name)
                {
                    return this.mPlayers[i];
                }
            }
            return null;
        }

        public bool LoadFrom(string fileName)
        {
            byte[] buffer = Tools.ReadFile(fileName);
            if (buffer == null)
            {
                return false;
            }
            MemoryStream input = new MemoryStream(buffer);
            object mLock = this.mLock;
            Monitor.Enter(mLock);
            try
            {
                BinaryReader reader = new BinaryReader(input);
                int num = reader.ReadInt32();
                for (int i = 0; i < num; i++)
                {
                    bool flag;
                    int channelID = reader.ReadInt32();
                    Channel channel = this.CreateChannel(channelID, out flag);
                    if (flag)
                    {
                        channel.LoadFrom(reader);
                    }
                }
            }
            catch (Exception exception)
            {
                base.Error("Loading from " + fileName + ": " + exception.Message);
                return false;
            }
            finally
            {
                Monitor.Exit(mLock);
            }
            return true;
        }

        public void MakePrivate()
        {
            this.mListenerPort = 0;
        }

        private void ProcessChannelPacket(TcpPlayer player, TNet.Buffer buffer, BinaryReader reader, Packet request)
        {
            switch (request)
            {
                case Packet.RequestLeaveChannel:
                    this.SendLeaveChannel(player, true);
                    break;

                case Packet.RequestCloseChannel:
                    player.channel.persistent = false;
                    player.channel.closed = true;
                    break;

                case Packet.RequestSetPlayerLimit:
                    player.channel.playerLimit = reader.ReadUInt16();
                    break;

                case Packet.RequestLoadLevel:
                    if (player.channel.host == player)
                    {
                        player.channel.Reset();
                        player.channel.level = reader.ReadString();
                        this.BeginSend(Packet.ResponseLoadLevel).Write(!string.IsNullOrEmpty(player.channel.level) ? player.channel.level : string.Empty);
                        this.EndSend(true, player.channel, null);
                    }
                    break;

                case Packet.RequestSetHost:
                    if (player.channel.host == player)
                    {
                        TcpPlayer player2 = this.GetPlayer(reader.ReadInt32());
                        if ((player2 != null) && (player2.channel == player.channel))
                        {
                            this.SendSetHost(player2);
                        }
                    }
                    break;

                case Packet.RequestRemoveRFC:
                {
                    uint inID = reader.ReadUInt32();
                    string funcName = ((inID & 0xff) != 0) ? null : reader.ReadString();
                    player.channel.DeleteRFC(inID, funcName);
                    break;
                }
                case Packet.RequestCreate:
                {
                    ushort num = reader.ReadUInt16();
                    byte num2 = reader.ReadByte();
                    uint num3 = 0;
                    if (num2 != 0)
                    {
                        num3 = --player.channel.objectCounter;
                        if (num3 < 0x8000)
                        {
                            player.channel.objectCounter = 0xffffff;
                            num3 = 0xffffff;
                        }
                        Channel.CreatedObject item = new Channel.CreatedObject {
                            playerID = player.id,
                            objectID = num,
                            uniqueID = num3,
                            type = num2
                        };
                        if (buffer.size > 0)
                        {
                            item.buffer = buffer;
                            buffer.MarkAsUsed();
                        }
                        player.channel.created.Add(item);
                    }
                    BinaryWriter writer = this.BeginSend(Packet.ResponseCreate);
                    writer.Write(player.id);
                    writer.Write(num);
                    writer.Write(num3);
                    if (buffer.size > 0)
                    {
                        writer.Write(buffer.buffer, buffer.position, buffer.size);
                    }
                    this.EndSend(true, player.channel, null);
                    break;
                }
                case Packet.RequestDestroy:
                {
                    uint uniqueID = reader.ReadUInt32();
                    if (player.channel.DestroyObject(uniqueID))
                    {
                        BinaryWriter writer2 = this.BeginSend(Packet.ResponseDestroy);
                        writer2.Write((ushort) 1);
                        writer2.Write(uniqueID);
                        this.EndSend(true, player.channel, null);
                    }
                    break;
                }
                case Packet.RequestSetChannelData:
                    player.channel.data = reader.ReadString();
                    this.BeginSend(Packet.ResponseSetChannelData).Write(player.channel.data);
                    this.EndSend(true, player.channel, null);
                    break;
            }
        }

        private void ProcessForwardPacket(TcpPlayer player, TNet.Buffer buffer, BinaryReader reader, Packet request, bool reliable)
        {
            if (!this.mUdp.isActive || (buffer.size > 0x400))
            {
                reliable = true;
            }
            switch (request)
            {
                case Packet.ForwardToHost:
                    buffer.position -= 5;
                    if ((!reliable && player.udpIsUsable) && ((player.channel.host.udpEndPoint != null) && this.mAllowUdp))
                    {
                        this.mUdp.Send(buffer, player.channel.host.udpEndPoint);
                        return;
                    }
                    player.channel.host.SendTcpPacket(buffer);
                    return;

                case Packet.ForwardToPlayerBuffered:
                {
                    int num = buffer.position - 5;
                    TcpPlayer player2 = this.GetPlayer(reader.ReadInt32());
                    uint inID = reader.ReadUInt32();
                    string funcName = ((inID & 0xff) != 0) ? null : reader.ReadString();
                    buffer.position = num;
                    player.channel.CreateRFC(inID, funcName, buffer);
                    if ((player2 != null) && player2.isConnected)
                    {
                        if ((!reliable && player2.udpIsUsable) && ((player2.udpEndPoint != null) && this.mAllowUdp))
                        {
                            this.mUdp.Send(buffer, player2.udpEndPoint);
                            return;
                        }
                        player2.SendTcpPacket(buffer);
                    }
                    return;
                }
            }
            TcpPlayer player3 = ((request != Packet.ForwardToOthers) && (request != Packet.ForwardToOthersSaved)) ? null : player;
            int num3 = buffer.position - 5;
            if ((request == Packet.ForwardToAllSaved) || (request == Packet.ForwardToOthersSaved))
            {
                uint num4 = reader.ReadUInt32();
                string str2 = ((num4 & 0xff) != 0) ? null : reader.ReadString();
                buffer.position = num3;
                player.channel.CreateRFC(num4, str2, buffer);
            }
            else
            {
                buffer.position = num3;
            }
            for (int i = 0; i < player.channel.players.size; i++)
            {
                TcpPlayer player4 = player.channel.players[i];
                if (player4 != player3)
                {
                    if ((reliable || !player4.udpIsUsable) || ((player4.udpEndPoint == null) || !this.mAllowUdp))
                    {
                        player4.SendTcpPacket(buffer);
                    }
                    else
                    {
                        this.mUdp.Send(buffer, player4.udpEndPoint);
                    }
                }
            }
        }

        private bool ProcessPlayerPacket(TNet.Buffer buffer, TcpPlayer player, bool reliable)
        {
            int id;
            string str;
            string str2;
            bool flag;
            ushort num4;
            bool flag2;
            if (player.stage == TcpProtocol.Stage.Verifying)
            {
                if (player.VerifyRequestID(buffer, true))
                {
                    this.mDictionaryID.Add(player.id, player);
                    if (this.onPlayerConnect != null)
                    {
                        this.onPlayerConnect(player);
                    }
                    return true;
                }
                this.RemovePlayer(player);
                return false;
            }
            BinaryReader reader = buffer.BeginReading();
            Packet request = (Packet) reader.ReadByte();
            Packet packet2 = request;
            switch (packet2)
            {
                case Packet.Empty:
                    goto Label_0919;

                case Packet.Error:
                    this.Error(player, reader.ReadString());
                    goto Label_0919;

                case Packet.Disconnect:
                    this.RemovePlayer(player);
                    goto Label_0919;

                case Packet.RequestPing:
                    this.BeginSend(Packet.ResponsePing);
                    this.EndSend(true, player);
                    goto Label_0919;

                case Packet.RequestSetUDP:
                {
                    int port = reader.ReadUInt16();
                    if ((port != 0) && this.mUdp.isActive)
                    {
                        IPAddress address = new IPAddress(player.tcpEndPoint.Address.GetAddressBytes());
                        this.SetPlayerUdpEndPoint(player, new IPEndPoint(address, port));
                    }
                    else
                    {
                        this.SetPlayerUdpEndPoint(player, null);
                    }
                    ushort num2 = !this.mUdp.isActive ? ((ushort) 0) : ((ushort) this.mUdp.listeningPort);
                    this.BeginSend(Packet.ResponseSetUDP).Write(num2);
                    this.EndSend(true, player);
                    if (player.udpEndPoint != null)
                    {
                        this.mUdp.SendEmptyPacket(player.udpEndPoint);
                    }
                    goto Label_0919;
                }
                case Packet.RequestJoinChannel:
                    id = reader.ReadInt32();
                    str = reader.ReadString();
                    str2 = reader.ReadString();
                    flag = reader.ReadBoolean();
                    num4 = reader.ReadUInt16();
                    if (id != -2)
                    {
                        goto Label_0301;
                    }
                    flag2 = string.IsNullOrEmpty(str2);
                    id = -1;
                    for (int i = 0; i < this.mChannels.size; i++)
                    {
                        Channel channel = this.mChannels[i];
                        if ((channel.isOpen && (flag2 || str2.Equals(channel.level))) && (string.IsNullOrEmpty(channel.password) || (channel.password == str)))
                        {
                            id = channel.id;
                            break;
                        }
                    }
                    break;

                case Packet.RequestSetName:
                {
                    player.name = reader.ReadString();
                    BinaryWriter writer4 = this.BeginSend(Packet.ResponseRenamePlayer);
                    writer4.Write(player.id);
                    writer4.Write(player.name);
                    if (player.channel == null)
                    {
                        this.EndSend(true, player);
                    }
                    else
                    {
                        this.EndSend(true, player.channel, null);
                    }
                    goto Label_0919;
                }
                case Packet.RequestSaveFile:
                {
                    string fileName = reader.ReadString();
                    byte[] data = reader.ReadBytes(reader.ReadInt32());
                    base.SaveFile(fileName, data);
                    goto Label_0919;
                }
                case Packet.RequestLoadFile:
                {
                    string str4 = reader.ReadString();
                    byte[] buffer3 = base.LoadFile(str4);
                    BinaryWriter writer5 = this.BeginSend(Packet.ResponseLoadFile);
                    writer5.Write(str4);
                    if (buffer3 == null)
                    {
                        writer5.Write(0);
                    }
                    else
                    {
                        writer5.Write(buffer3.Length);
                        writer5.Write(buffer3);
                    }
                    this.EndSend(true, player);
                    goto Label_0919;
                }
                case Packet.RequestDeleteFile:
                    base.DeleteFile(reader.ReadString());
                    goto Label_0919;

                case Packet.RequestNoDelay:
                    player.noDelay = reader.ReadBoolean();
                    goto Label_0919;

                case Packet.RequestChannelList:
                {
                    BinaryWriter writer6 = this.BeginSend(Packet.ResponseChannelList);
                    int num9 = 0;
                    for (int j = 0; j < this.mChannels.size; j++)
                    {
                        if (!this.mChannels[j].closed)
                        {
                            num9++;
                        }
                    }
                    writer6.Write(num9);
                    for (int k = 0; k < this.mChannels.size; k++)
                    {
                        Channel channel3 = this.mChannels[k];
                        if (!channel3.closed)
                        {
                            writer6.Write(channel3.id);
                            writer6.Write((ushort) channel3.players.size);
                            writer6.Write(channel3.playerLimit);
                            writer6.Write(!string.IsNullOrEmpty(channel3.password));
                            writer6.Write(channel3.persistent);
                            writer6.Write(channel3.level);
                            writer6.Write(channel3.data);
                        }
                    }
                    this.EndSend(true, player);
                    goto Label_0919;
                }
                default:
                    switch (packet2)
                    {
                        case Packet.ForwardToPlayer:
                        {
                            TcpPlayer player4 = this.GetPlayer(reader.ReadInt32());
                            if ((player4 != null) && player4.isConnected)
                            {
                                buffer.position -= 9;
                                player4.SendTcpPacket(buffer);
                            }
                            goto Label_0919;
                        }
                        case Packet.ForwardToPlayerBuffered:
                        case Packet.RequestAddServer:
                        case Packet.RequestRemoveServer:
                        case Packet.RequestServerList:
                        case Packet.ResponseServerList:
                            goto Label_08BF;

                        case Packet.RequestSetTimeout:
                            player.timeoutTime = reader.ReadInt32() * 0x3e8;
                            goto Label_0919;

                        case Packet.Broadcast:
                            buffer.position -= 5;
                            for (int m = 0; m < this.mPlayers.size; m++)
                            {
                                TcpPlayer player6 = this.mPlayers[m];
                                if ((reliable || !player6.udpIsUsable) || ((player6.udpEndPoint == null) || !this.mAllowUdp))
                                {
                                    player6.SendTcpPacket(buffer);
                                }
                                else
                                {
                                    this.mUdp.Send(buffer, player6.udpEndPoint);
                                }
                            }
                            goto Label_0919;

                        case Packet.RequestActivateUDP:
                            player.udpIsUsable = true;
                            if (player.udpEndPoint != null)
                            {
                                this.mUdp.SendEmptyPacket(player.udpEndPoint);
                            }
                            goto Label_0919;

                        case Packet.SyncPlayerData:
                        {
                            int num7 = buffer.position - 5;
                            TcpPlayer player2 = this.GetPlayer(reader.ReadInt32());
                            if (player2 != null)
                            {
                                if (buffer.size > 1)
                                {
                                    player2.data = reader.ReadObject();
                                }
                                else
                                {
                                    player2.data = null;
                                }
                                if (player2.channel != null)
                                {
                                    buffer.position = num7;
                                    for (int n = 0; n < player2.channel.players.size; n++)
                                    {
                                        TcpPlayer player3 = player2.channel.players[n];
                                        if (player3 != player)
                                        {
                                            if ((reliable || !player3.udpIsUsable) || ((player3.udpEndPoint == null) || !this.mAllowUdp))
                                            {
                                                player3.SendTcpPacket(buffer);
                                            }
                                            else
                                            {
                                                this.mUdp.Send(buffer, player3.udpEndPoint);
                                            }
                                        }
                                    }
                                }
                                else if (player2 != player)
                                {
                                    buffer.position = num7;
                                    player2.SendTcpPacket(buffer);
                                }
                            }
                            goto Label_0919;
                        }
                        case Packet.ForwardByName:
                        {
                            int num12 = buffer.position - 5;
                            string name = reader.ReadString();
                            TcpPlayer player5 = this.GetPlayer(name);
                            if ((player5 == null) || !player5.isConnected)
                            {
                                if (reliable)
                                {
                                    this.BeginSend(Packet.ForwardTargetNotFound).Write(name);
                                    this.EndSend(true, player);
                                }
                            }
                            else
                            {
                                buffer.position = num12;
                                player5.SendTcpPacket(buffer);
                            }
                            goto Label_0919;
                        }
                        default:
                            goto Label_08BF;
                    }
                    break;
            }
            if (flag2 && (id == -1))
            {
                BinaryWriter writer = this.BeginSend(Packet.ResponseJoinChannel);
                writer.Write(false);
                writer.Write("No suitable channels found");
                this.EndSend(true, player);
                goto Label_0919;
            }
        Label_0301:
            if (id == -1)
            {
                id = this.mRandom.Next(0x5f5e100);
                for (int num6 = 0; num6 < 0x3e8; num6++)
                {
                    if (!this.ChannelExists(id))
                    {
                        break;
                    }
                    id = this.mRandom.Next(0x5f5e100);
                }
            }
            if ((player.channel == null) || (player.channel.id != id))
            {
                bool flag3;
                Channel channel2 = this.CreateChannel(id, out flag3);
                if ((channel2 == null) || !channel2.isOpen)
                {
                    BinaryWriter writer2 = this.BeginSend(Packet.ResponseJoinChannel);
                    writer2.Write(false);
                    writer2.Write("The requested channel is closed");
                    this.EndSend(true, player);
                }
                else if (flag3)
                {
                    channel2.password = str;
                    channel2.persistent = flag;
                    channel2.level = str2;
                    channel2.playerLimit = num4;
                    this.SendLeaveChannel(player, false);
                    this.SendJoinChannel(player, channel2);
                }
                else if (string.IsNullOrEmpty(channel2.password) || (channel2.password == str))
                {
                    this.SendLeaveChannel(player, false);
                    this.SendJoinChannel(player, channel2);
                }
                else
                {
                    BinaryWriter writer3 = this.BeginSend(Packet.ResponseJoinChannel);
                    writer3.Write(false);
                    writer3.Write("Wrong password");
                    this.EndSend(true, player);
                }
            }
            goto Label_0919;
        Label_08BF:
            if ((player.channel != null) && (request <= Packet.ForwardToPlayerBuffered))
            {
                if (request >= Packet.ForwardToAll)
                {
                    this.ProcessForwardPacket(player, buffer, reader, request, reliable);
                }
                else
                {
                    this.ProcessChannelPacket(player, buffer, reader, request);
                }
            }
            else if (this.onCustomPacket != null)
            {
                this.onCustomPacket(player, buffer, reader, request, reliable);
            }
        Label_0919:
            return true;
        }

        private void RemovePlayer(TcpPlayer p)
        {
            if (p != null)
            {
                this.SendLeaveChannel(p, false);
                p.Release();
                this.mPlayers.Remove(p);
                if (p.udpEndPoint != null)
                {
                    this.mDictionaryEP.Remove(p.udpEndPoint);
                    p.udpEndPoint = null;
                    p.udpIsUsable = false;
                }
                if (p.id != 0)
                {
                    if (this.mDictionaryID.Remove(p.id) && (this.onPlayerDisconnect != null))
                    {
                        this.onPlayerDisconnect(p);
                    }
                    p.id = 0;
                }
            }
        }

        public void SaveTo(string fileName)
        {
            if (this.mListener != null)
            {
                MemoryStream output = new MemoryStream();
                BinaryWriter writer = new BinaryWriter(output);
                object mLock = this.mLock;
                lock (mLock)
                {
                    writer.Write(0);
                    int num = 0;
                    for (int i = 0; i < this.mChannels.size; i++)
                    {
                        Channel channel = this.mChannels[i];
                        if ((!channel.closed && channel.persistent) && channel.hasData)
                        {
                            writer.Write(channel.id);
                            channel.SaveTo(writer);
                            num++;
                        }
                    }
                    if (num > 0)
                    {
                        output.Seek(0L, SeekOrigin.Begin);
                        writer.Write(num);
                    }
                }
                Tools.WriteFile(fileName, output.ToArray());
                output.Close();
            }
        }

        private void SendJoinChannel(TcpPlayer player, Channel channel)
        {
            if ((player.channel == null) || (player.channel != channel))
            {
                player.channel = channel;
                player.FinishJoiningChannel();
                BinaryWriter bw = this.BeginSend(Packet.ResponsePlayerJoined);
                bw.Write(player.id);
                bw.Write(!string.IsNullOrEmpty(player.name) ? player.name : "Guest");
                bw.WriteObject(player.data);
                this.EndSend(true, channel, null);
                channel.players.Add(player);
            }
        }

        private void SendLeaveChannel(TcpPlayer player, bool notify)
        {
            Channel channel = player.channel;
            if (channel != null)
            {
                channel.RemovePlayer(player, this.mTemp);
                player.channel = null;
                if (channel.players.size > 0)
                {
                    if (this.mTemp.size > 0)
                    {
                        BinaryWriter writer = this.BeginSend(Packet.ResponseDestroy);
                        writer.Write((ushort) this.mTemp.size);
                        for (int i = 0; i < this.mTemp.size; i++)
                        {
                            writer.Write(this.mTemp[i]);
                        }
                        this.EndSend(true, channel, null);
                    }
                    if (channel.host == null)
                    {
                        this.SendSetHost(channel.players[0]);
                    }
                    this.BeginSend(Packet.ResponsePlayerLeft).Write(player.id);
                    this.EndSend(true, channel, null);
                }
                else if (!channel.persistent)
                {
                    this.mChannels.Remove(channel);
                }
                if (notify && player.isConnected)
                {
                    this.BeginSend(Packet.ResponseLeaveChannel);
                    this.EndSend(true, player);
                }
            }
        }

        private void SendSetHost(TcpPlayer player)
        {
            if ((player.channel != null) && (player.channel.host != player))
            {
                player.channel.host = player;
                this.BeginSend(Packet.ResponseSetHost).Write(player.id);
                this.EndSend(true, player.channel, null);
            }
        }

        private void SendToChannel(bool reliable, Channel channel, TNet.Buffer buffer)
        {
            this.mBuffer.MarkAsUsed();
            if (this.mBuffer.size > 0x400)
            {
                reliable = true;
            }
            for (int i = 0; i < channel.players.size; i++)
            {
                TcpPlayer player = channel.players[i];
                if (player.stage == TcpProtocol.Stage.Connected)
                {
                    if ((reliable || !player.udpIsUsable) || ((player.udpEndPoint == null) || !this.mAllowUdp))
                    {
                        player.SendTcpPacket(this.mBuffer);
                    }
                    else
                    {
                        this.mUdp.Send(this.mBuffer, player.udpEndPoint);
                    }
                }
            }
            this.mBuffer.Recycle();
        }

        private void SetPlayerUdpEndPoint(TcpPlayer player, IPEndPoint udp)
        {
            if (player.udpEndPoint != null)
            {
                this.mDictionaryEP.Remove(player.udpEndPoint);
            }
            player.udpEndPoint = udp;
            player.udpIsUsable = false;
            if (udp != null)
            {
                this.mDictionaryEP[udp] = player;
            }
        }

        public bool Start(int tcpPort)
        {
            return this.Start(tcpPort, 0);
        }

        public bool Start(int tcpPort, int udpPort)
        {
            this.Stop();
            try
            {
                this.mListenerPort = tcpPort;
                this.mListener = new TcpListener(IPAddress.Any, tcpPort);
                this.mListener.Start(50);
            }
            catch (Exception exception)
            {
                base.Error(exception.Message);
                return false;
            }
            if (!this.mUdp.Start(udpPort))
            {
                base.Error("Unable to listen to UDP port " + udpPort);
                this.Stop();
                return false;
            }
            this.mAllowUdp = udpPort > 0;
            return true;
        }

        public void Stop()
        {
            this.mAllowUdp = false;
            if (this.mThread != null)
            {
                this.mThread.Abort();
                this.mThread = null;
            }
            if (this.mListener != null)
            {
                this.mListener.Stop();
                this.mListener = null;
            }
            this.mUdp.Stop();
            int size = this.mPlayers.size;
            while (size > 0)
            {
                this.RemovePlayer(this.mPlayers[--size]);
            }
            this.mChannels.Clear();
        }

        private void ThreadFunction()
        {
            bool flag = false;
            object mLock = this.mLock;
            lock (mLock)
            {
                TNet.Buffer buffer;
                IPEndPoint point;
                this.mTime = DateTime.UtcNow.Ticks / 0x2710L;
                if (this.mListenerPort != 0)
                {
                    goto Label_0084;
                }
                if (this.mListener != null)
                {
                    this.mListener.Stop();
                    this.mListener = null;
                    if (this.onShutdown != null)
                    {
                        this.onShutdown();
                    }
                }
                goto Label_0216;
            Label_0072:
                this.AddPlayer(this.mListener.AcceptSocket());
            Label_0084:
                if ((this.mListener != null) && this.mListener.Pending())
                {
                    goto Label_0072;
                }
            Label_0216:
                while ((this.mUdp.listeningPort != 0) && this.mUdp.ReceivePacket(out buffer, out point))
                {
                    if (buffer.size > 0)
                    {
                        TcpPlayer player = this.GetPlayer(point);
                        if (player != null)
                        {
                            if (!player.udpIsUsable)
                            {
                                player.udpIsUsable = true;
                            }
                            try
                            {
                                if (this.ProcessPlayerPacket(buffer, player, false))
                                {
                                    flag = true;
                                }
                            }
                            catch (Exception exception)
                            {
                                base.Error("(ThreadFunction Process) " + exception.Message + "\n" + exception.StackTrace);
                                this.RemovePlayer(player);
                            }
                        }
                        else if (buffer.size > 4)
                        {
                            Packet empty = Packet.Empty;
                            try
                            {
                                BinaryReader reader = buffer.BeginReading();
                                empty = (Packet) reader.ReadByte();
                                switch (empty)
                                {
                                    case Packet.RequestActivateUDP:
                                    {
                                        int id = reader.ReadInt32();
                                        player = this.GetPlayer(id);
                                        if (((player != null) && (player.udpEndPoint != null)) && (player.udpEndPoint.Address == point.Address))
                                        {
                                            player.udpEndPoint = point;
                                            player.udpIsUsable = true;
                                            this.mUdp.SendEmptyPacket(player.udpEndPoint);
                                        }
                                        goto Label_020F;
                                    }
                                    case Packet.RequestPing:
                                        this.BeginSend(Packet.ResponsePing);
                                        this.EndSend(point);
                                        goto Label_020F;
                                }
                            }
                            catch (Exception exception2)
                            {
                                base.Error(string.Concat(new object[] { "(ThreadFunction Read ", empty, ") ", exception2.Message }));
                                this.RemovePlayer(player);
                            }
                        }
                    }
                Label_020F:
                    buffer.Recycle();
                }
                int num2 = 0;
                while (num2 < this.mPlayers.size)
                {
                    TcpPlayer player2 = this.mPlayers[num2];
                    for (int i = 0; (i < 100) && player2.ReceivePacket(out buffer); i++)
                    {
                        if ((buffer.size > 0) && this.ProcessPlayerPacket(buffer, player2, true))
                        {
                            flag = true;
                        }
                        buffer.Recycle();
                    }
                    if (player2.stage == TcpProtocol.Stage.Connected)
                    {
                        if ((player2.timeoutTime <= 0L) || ((player2.lastReceivedTime + player2.timeoutTime) >= this.mTime))
                        {
                            goto Label_0307;
                        }
                        this.RemovePlayer(player2);
                        continue;
                    }
                    if ((player2.lastReceivedTime + 0x7d0L) < this.mTime)
                    {
                        this.RemovePlayer(player2);
                        continue;
                    }
                Label_0307:
                    num2++;
                }
            }
        }

        public void Update()
        {
            if ((this.mThread == null) && (this.mListener != null))
            {
                this.ThreadFunction();
            }
        }

        public bool isActive
        {
            get
            {
                return (this.mThread != null);
            }
        }

        public bool isListening
        {
            get
            {
                return (this.mListener != null);
            }
        }

        public int playerCount
        {
            get
            {
                return (!this.isActive ? 0 : this.mPlayers.size);
            }
        }

        public int tcpPort
        {
            get
            {
                return ((this.mListener == null) ? 0 : this.mListenerPort);
            }
        }

        public int udpPort
        {
            get
            {
                return this.mUdp.listeningPort;
            }
        }

        public delegate void OnCustomPacket(TcpPlayer player, TNet.Buffer buffer, BinaryReader reader, Packet request, bool reliable);

        public delegate void OnPlayerAction(Player p);

        public delegate void OnShutdown();
    }
}

